package com.inepex.inechart.client.axes;

import java.util.ArrayList;
import java.util.List;

import com.inepex.inechart.shared.axes.Axis;
import com.inepex.inegraphics.impl.client.DrawingAreaGWT;
import com.inepex.inegraphics.impl.client.IncrementalProgressCallerImpl;
import com.inepex.inegraphics.impl.client.IncrementalProgress.IncrementalProgressCaller;

public abstract class IncrementalAxisDrawer implements IncrementalProgressCaller{

	public interface DrawingAreaProviderForAxis{
		DrawingAreaGWT getGridAndFillDrawingAreaForAxis(Axis axis);
		DrawingAreaGWT getAxisAndTickLineDrawingAreaForAxis(Axis axis);
		DrawingAreaGWT getTickTextDrawingAreaForAxis(Axis axis);
	}

	protected enum AxisComponent{
		axis_and_tick_lines,
		grids_and_gridfills,
		tick_texts
	}
	
	protected class AxisComponentTargetMap{
		Axis axis;
		AxisComponent axisComponent;
		DrawingAreaGWT target;
		public AxisComponentTargetMap(Axis axis, AxisComponent axisComponent,
				DrawingAreaGWT target) {
			super();
			this.axis = axis;
			this.axisComponent = axisComponent;
			this.target = target;
		}
		
	}

	protected DrawingAreaProviderForAxis drawingAreaProviderForAxis;
	protected List<Axis> axesToDraw;
	protected int updatePartTreshold;
	protected AxesGWT axesGwt;
	protected IncrementalProgressCallerImpl drawingAreaUpdater;
	protected int actualTargetIndex;
	protected DrawingAreaGWT actualTarget;
	protected ArrayList<AxisComponentTargetMap> targets;

	public IncrementalAxisDrawer(AxesGWT axesGwt, List<Axis> axesToDraw, int updatePartTreshold, DrawingAreaProviderForAxis drawingAreaProviderForAxis){
		this.axesToDraw = axesToDraw;
		this.axesGwt = axesGwt;
		this.updatePartTreshold = updatePartTreshold;
		actualTargetIndex = 0;
		this.drawingAreaProviderForAxis = drawingAreaProviderForAxis;
		targets = new ArrayList<AxisComponentTargetMap>();
		collectTargets();
		if(next()){
			startNext();
		}
		else{
			onFinish();
		}
	}

	@Override
	public int getProgressPartTresholdMS() {
		return updatePartTreshold;
	}
	
	protected void collectTargets(){
		for (Axis axis : axesToDraw) {
			//TODO consider incremental GO to Canvas adding (e.g. may be a big chunk of time adding 10K objects...) 
			AxisComponentTargetMap map = new AxisComponentTargetMap(axis, AxisComponent.grids_and_gridfills, drawingAreaProviderForAxis.getGridAndFillDrawingAreaForAxis(axis));
			map.target.add(axesGwt.axisToAxisCalcMap.get(axis).getGridLinesAndFills());
			targets.add(map);
			
			map = new AxisComponentTargetMap(axis, AxisComponent.axis_and_tick_lines, drawingAreaProviderForAxis.getAxisAndTickLineDrawingAreaForAxis(axis));
			map.target.add(axesGwt.axisToAxisCalcMap.get(axis).getAxisLineAndTickGOs());
			targets.add(map);
			
			map = new AxisComponentTargetMap(axis, AxisComponent.tick_texts, drawingAreaProviderForAxis.getTickTextDrawingAreaForAxis(axis));
			map.target.add(axesGwt.axisToAxisCalcMap.get(axis).getTexts());
			targets.add(map);
		}
	}

	protected boolean next(){
		if(targets.size() > actualTargetIndex){
			actualTarget = targets.get(actualTargetIndex++).target;
			return true;
		}
		else{
			return false;
		}
	}

	protected void startNext(){
		drawingAreaUpdater = new IncrementalProgressCallerImpl(actualTarget, updatePartTreshold) {

			@Override
			public void onFinished() {
				if(next()){
					startNext();
				}
				else{
					onFinish();
				}
			}
		};
	}

	public abstract void onFinish();
}
